//ECE 454 Spring 2008 Assignment 1
//Macaranas, Joseph jjmacara
//Turner, Travis t2turner
#ifndef __MARSHAL_H__
#define __MARSHAL_H__

#include "RPCheader.h"

//custom struct used to form the messages between the binder and servers/clients
struct binder_msg {
	int requestType; //flag to determine type of request message is
	char *name; //name of function to be registered by server or being looked up by client
	int *argTypes; //argument types that are part of the function to being looked up or registered
	function *functions; //array of functions to return to client lookups
	unsigned long *servers; //array of server ip addresses to return to client lookups
};

//struct for linked-list of server information corresponding to argTypes
//the name is derived from the map that uses this struct
//map will point to head of the linked list
struct server_list {
	int *argTypes; //argument types, each linked list node has different argTypes
	function *functions; //array of functions that implement this linked list's node name-argTypes pair
	unsigned long *servers; //array of the unsigned long representation of ip addresses of the servers
	//that implement this linked-list's node name-argTypes pair
	server_list *next; //used to go to next node in linked list
};

struct thread_data {
   int *argTypes;		//the types of arguments
   void **args;			//the arguments themselves
   function f;			//the function pointer to the rpc method
   int  len;
   int thread_id;
   struct   sockaddr_in return_addr;     /* structure to hold return address */
   void *message;
};

//global functions

/****************************************************************************
	THIS FUNCTION ALLOWS BOTH THE CLIENT AND SERVER TO PACK
	GENERIC DATA INTO A VOID * MESSAGE
	ADDRESS OF MESSAGE AND MESSAGE LENGTH VARIABLES ARE
	PASSED AS PARAMETERS BY REFERENCE

	Each case follows a similar pattern.  First, a temporary pointer
	is pointed to the current (empty) index of the message.  Then, the
	relevant data is copied to this location.  The temporary pointer is
	then incremented, and the index pointer is updated to point at the
	new (free) location.
****************************************************************************/

int rpcPackData(int *argTypes, void **args, void *message, int *msgLength, function *f = NULL) {

	void *msgPtr = message;					//pointer to traverse message

	*msgLength = 0;

	int numParams = 0;

	//marshalling of parameters...
	for(; argTypes[numParams] != 0; numParams++) {
		int *tempPtr = (int *)msgPtr;

		*tempPtr = argTypes[numParams];	//assign the value in argTypes to the value pointed to by msgptr
		tempPtr++;
		msgPtr = (void *) tempPtr;
		*msgLength += sizeof(int);				//add 4 bytes to size of overall message
	}
	//use padding of one 0 int at end of argTypes array
	int *tempPtr = (int *)msgPtr;	//get a pointer to current location
	*tempPtr = 0;					//pad with 32 zeros
	tempPtr++;						//increment the pointer
	msgPtr = (void *)tempPtr;		//update index pointer location
	*msgLength += sizeof(int);		//increment message size by 4 bytes

	//loop through the list of parameters
	for(int j = 0; j < numParams; j++) {

		//the argument is an array in this case
		if((argTypes[j] & 0xFFFF) > 1) {

			int numElements = argTypes[j] & 0xFFFF;		//get the number of elements by masking appropriate bits in argTypes

			switch(argTypes[j] & 0xFF0000) {
			case rpcChar:
			{
				char *tempPtr = (char *)msgPtr;
				for(int i = 0; i < numElements; i++) {
					*tempPtr = ((char *)args[j])[i]; //assign value of char to value pointed to by msgPtr
					tempPtr++;
					*msgLength += sizeof(char);				//increment message size
				}
				//if odd number of elements, pad message for memory address alignment
				if (numElements % 4 != 0) {
					for(int i = 0; i < 4 - (numElements % 4); i++) {
						*tempPtr = 0;
						tempPtr++;
						*msgLength += sizeof(char);
					}
				}
				msgPtr = (void *)tempPtr;
			}
			break;

			case rpcShort:
				for(int i = 0; i < numElements; i++) {
					short *tempPtr = (short *)msgPtr;
					*tempPtr = ((short *)args[j])[i]; //assign value of short to value pointed to by msgPtr
					tempPtr++;
					msgPtr = (void *)tempPtr;
					*msgLength += sizeof(short);				//increment message size
				}
				//this is to handle alignment of shorts that fall on a 4-byte boundary
				//the next piece of data to be marshalled will be unaligned
				if (numElements % 2 != 0) {
					short *sh;
					sh = (short *)msgPtr;
					*sh = 0;				//pad with 2 bytes of zeros
					sh++;
					*msgLength += sizeof(short);
					msgPtr = (void *)sh;
				}
			break;

			case rpcInt:
				for(int i = 0; i < numElements; i++) {
					int  *tempPtr = (int *)msgPtr;
					*tempPtr = ((int *)args[j])[i]; //assign value of int to value pointed to by msgPtr
					tempPtr++;
					msgPtr = (void *)tempPtr;
					*msgLength += sizeof(int);				//increment message size
				}
			break;

			case rpcLong:
				for(int i = 0; i < numElements; i++) {
					long  *tempPtr = (long *)msgPtr;
					*tempPtr = ((long *)args[j])[i]; //assign value of long to value pointed to by msgPtr
					tempPtr++;
					msgPtr = (void *)tempPtr;
					*msgLength += sizeof(long);			//increment message size
				}
			break;

			case rpcFloat:
				for(int i = 0; i < numElements; i++) {
					float  *tempPtr = (float *)msgPtr;
					*tempPtr = ((float *)args[j])[i]; //assign value of float to value pointed to by msgPtr
					tempPtr++;
					msgPtr = (void *)tempPtr;
					*msgLength += sizeof(float);				//increment message size
				}
			break;

			case rpcDouble:
				for(int i = 0; i < numElements; i++) {
					double  *tempPtr = (double *)msgPtr;
					*tempPtr = ((double *)args[j])[i]; //assign value of double to value pointed to by msgPtr
					tempPtr++;
					msgPtr = (void *)tempPtr;
					*msgLength += sizeof(double);	//increment message size
				}
			break;

			case rpcString:
				for(int i = 0; i < numElements; i++) {
					int cStrLen = 0;
					char *tempPtr = (char *)msgPtr;				//get a pointer to the current index
					char *stringPtr = ((char **)args[j])[i];	//get a pointer to the first string
					for(; *stringPtr != '\0'; stringPtr++) {	//loop until null character
					 	*tempPtr = *stringPtr;					//assign character to current index
					 	tempPtr++;								//increment index
					 	*msgLength += sizeof(char);				//jncrement message size
						cStrLen++;								//keep track of string length
					}
					*tempPtr = '\0';	//NULL TERMINATE
					tempPtr++;
					cStrLen++;
					*msgLength += sizeof(char);
					if (cStrLen % 4 != 0) {						//if the length is not aligned, pad with the required # of 0's
						for(int i = 0; i < 4 - (cStrLen % 4); i++) {
							*tempPtr = 0;
							tempPtr++;
							*msgLength += sizeof(char);
						}
					}
					msgPtr = (void *)tempPtr;
				}
			break;

			default:
				cerr << "Unknown parameter type!" << std::endl;
				return RESULT_FAILURE;
			break;
			} //end switch

		} else {	//single argument case
			switch(argTypes[j] & 0xFF0000) {
			case rpcChar:
			{
				char *tempPtr = (char *)msgPtr;
				*tempPtr = *(char *)args[j];
				tempPtr++;
				*msgLength += sizeof(char);
				//always an odd address after 1 char, pad with three 0's for address alignment
				*tempPtr = 0;
				tempPtr++;
				*msgLength += sizeof(char);
				*tempPtr = 0;
				tempPtr++;
				*msgLength += sizeof(char);
				*tempPtr = 0;
				tempPtr++;
				*msgLength += sizeof(char);
				msgPtr = (void *)tempPtr;
			}
			break;

			case rpcShort:
			{
				short *tempPtr = (short *)msgPtr;
				*tempPtr = *(short *)args[j];
				tempPtr++;
				*msgLength += sizeof(short);
				//realign memory address by adding another short
				*tempPtr = 0;
				tempPtr++;
				*msgLength += sizeof(short);
				msgPtr = (void *)tempPtr;
			}
			break;

			case rpcInt:
			{
				int *tempPtr = (int *)msgPtr;
				*tempPtr = *(int *)args[j]; //assign value of int to value pointed to by msgPtr
				tempPtr++;
				msgPtr = (void *)tempPtr;
				*msgLength += sizeof(int);
			}
			break;
			case rpcLong:
			{
				long *tempPtr = (long *)msgPtr;
				*tempPtr = *(long *)args[j]; //assign value of long to value polonged to by msgPtr
				tempPtr++;
				msgPtr = (void *)tempPtr;
				*msgLength += sizeof(long);
			}
			break;

			case rpcFloat:
			{
				float *tempPtr = (float *)msgPtr;
				*tempPtr = *(float *)args[j]; //assign value of float to value pofloated to by msgPtr
				tempPtr++;
				msgPtr = (void *)tempPtr;
				*msgLength += sizeof(float);
			}
			break;

			case rpcDouble:
			{
				double *tempPtr = (double *)msgPtr;
				*tempPtr = *(double *)args[j]; //assign value of double to value podoubleed to by msgPtr
				tempPtr++;
				msgPtr = (void *)tempPtr;
				*msgLength += sizeof(double);
			}
			break;

			case rpcString:
			{
				int cStrLen = 0;
				char *stringPtr = (char *)args[j];
				char *tempPtr = (char *)msgPtr;
				for(; *stringPtr != '\0'; stringPtr++) {
					*tempPtr = *stringPtr;
					tempPtr++;
					cStrLen++;
					*msgLength += sizeof(char);
				}
				*tempPtr = '\0';
				tempPtr++;
				cStrLen++;
				*msgLength += sizeof(char);
				if (cStrLen % 4 != 0) {
					for(int i = 0; i < 4 - (cStrLen % 4); i++) {
						*tempPtr = 0;
						tempPtr++;
						*msgLength += sizeof(char);
					}
				}
				msgPtr = (void *)tempPtr;
			}
			break;

			default:
				cerr << "Unknown parameter type!" << std::endl;
				return RESULT_FAILURE;
			break;
			} //end switch
		}//end if
	}//end for

	if (f != NULL) {
		function *tempPtr = (function *)msgPtr;
		*tempPtr = *f;
		*msgLength += sizeof(function);
	} else {
		function *tempPtr = (function *)msgPtr;
		*tempPtr = 0;
		*msgLength += sizeof(function);
	}

	return RESULT_SUCCESS;
}

/****************************************************************************
	THIS FUNCTION ALLOWS BOTH THE CLIENT AND SERVER TO EXTRACT
	FORMATTED DATA FROM A VOID * MESSAGE
	THE DATA IS RETURNED IN A THREAD_DATA STRUCT PASSED BY REFERENCE
****************************************************************************/

int rpcExtractData(void *message, thread_data *unPackedData) {

	int numParams = 0, counter = 0; //counter used to keep track of amount read
	void *msgPtr = message;	//start at the beginning of the message

	//grab the number of parameters from the message
	int *temp_for_params = (int *)msgPtr;
	for(; *temp_for_params != 0; temp_for_params++) {
		numParams++;
		counter += sizeof(int);
	}

	int *argTypes = (int *)malloc((numParams + 1) * sizeof(int));
	void **args = (void **)malloc(numParams * sizeof(int));
	for(int i = 0; i < numParams; i++) {
		int *temp2 = (int *)msgPtr;
		argTypes[i] = *temp2;				//extract the argTypes
		temp2++;
		msgPtr = (void *)temp2;
	}
	//skip padding at the end, store the 0
	int *temp3 = (int *)msgPtr;
	temp3++;
	argTypes[numParams] = 0;
	msgPtr = (void *)temp3;
	counter += sizeof(int);

	for(int j = 0; j < numParams; j++) {

		//the argument is an array in this case
		if((argTypes[j] & 0xFFFF) > 1) {

			int numElements = argTypes[j] & 0xFFFF;

			switch(argTypes[j] & 0xFF0000) {
			case rpcChar:
			{
				char *tempCharArray = (char *)malloc(numElements * sizeof(char));
				for(int i = 0; i < numElements; i++) {
					char *temp_char = (char *)msgPtr;
					tempCharArray[i] = *temp_char;
					temp_char++;
					msgPtr = (void *) temp_char;
					counter += sizeof(char);
				}

				args[j] = tempCharArray;
				//skip the possible zeros used for padding to align addresses
				if (numElements % 4 != 0) {
					for(int i = 0; i < 4 - (numElements % 4); i++) {
						char *temp_char = (char *)msgPtr;
						temp_char++;
						msgPtr = (void *)temp_char;
						counter += sizeof(char);
					}
				}
			}
			break;

			case rpcShort:
			{
				short *tempShortArray = (short *)malloc(numElements * sizeof(short));
				for(int i = 0; i < numElements; i++) {
					short *temp_short = (short *)msgPtr;
					tempShortArray[i] = *temp_short;
					temp_short++;
					msgPtr = (void *) temp_short;
					counter += sizeof(short);
				}
				args[j] = tempShortArray;
				//skip possible zero
				if (numElements % 2 != 0) {
					short *temp_s = (short *)msgPtr;
					temp_s++;
					msgPtr = (void *)temp_s;
					counter += sizeof(short);
				}
			}
			break;

			case rpcInt:
			{
				int *tempintArray = (int *)malloc(numElements * sizeof(int));
				for(int i = 0; i < numElements; i++) {
					int *temp_int = (int *)msgPtr;
					tempintArray[i] = *temp_int;
					temp_int++;
					msgPtr = (void *) temp_int;
					counter += sizeof(int);
				}
				args[j] = tempintArray;
			}
			break;

			case rpcLong:
			{
				long *templongArray = (long *)malloc(numElements * sizeof(long));
				for(int i = 0; i < numElements; i++) {
					long *temp_long = (long *)msgPtr;
					templongArray[i] = *temp_long;
					temp_long++;
					msgPtr = (void *) temp_long;
					counter += sizeof(long);
				}
				args[j] = templongArray;
			}
			break;

			case rpcFloat:
			{
				float *tempfloatArray = (float *)malloc(numElements * sizeof(float));
				for(int i = 0; i < numElements; i++) {
					float *temp_float = (float *)msgPtr;
					tempfloatArray[i] = *temp_float;
					temp_float++;
					msgPtr = (void *) temp_float;
					counter += sizeof(float);
				}
				args[j] = tempfloatArray;
			}
			break;

			case rpcDouble:
			{
				double *tempdoubleArray = (double *)malloc(numElements * sizeof(double));
				for(int i = 0; i < numElements; i++) {
					double *temp_double = (double *)msgPtr;
					tempdoubleArray[i] = *temp_double;
					temp_double++;
					msgPtr = (void *) temp_double;
					counter += sizeof(double);
				}
				args[j] = tempdoubleArray;
			}
			break;

			case rpcString:
			{
				char **tempstringArray = (char **)malloc(numElements * sizeof(char *));
				for(int i = 0; i < numElements; i++) {
					char *tempString = (char *)msgPtr;
					int k = 0; //string length
					for(; *tempString != '\0'; tempString++, k++) { }
					tempString = (char *)malloc((k + 1) * sizeof(char));
					char *temp_char = (char*)msgPtr;
					for(int p = 0; p < k; p++) {
						tempString[p] = *temp_char;
						temp_char++;
						counter += sizeof(char);
					}
					//add in the null terminator
					tempString[k] = '\0';
					temp_char++;
					counter += sizeof(char);
					k++;
					//skip zero if name was padded for memory address alignment
					if (k % 4 != 0) { //equivalent to (k-1) % 4 == 0
						for(int i = 0; i < 4-(k % 4); i++) {
							temp_char++;
							counter += sizeof(char);
						}
					}
					msgPtr = (void *) temp_char;
					tempstringArray[i] = tempString;
				}
				args[j] = tempstringArray;	//assign to args pointer
			}
			break;

			default:
				cerr << "Unknown parameter type!" << endl;
				return RESULT_FAILURE;
			break;
			} //end switch
		} else {
			switch(argTypes[j] & 0xFF0000) {
			case rpcChar:
			{
				char *t_c = (char *)msgPtr;
				args[j] = (void *)t_c;
				t_c++;
				counter += sizeof(char);
				//skip the padding
				t_c++; t_c++; t_c++;
				msgPtr = (void *)t_c;
				counter += 3 * sizeof(char);
			}
			break;

			case rpcShort:
			{
				short *t_s = (short *)msgPtr;
				*(short *)args[j] = *t_s;
				t_s++;
				msgPtr = (void *)t_s;
				counter += sizeof(short);
				//skip padding
				t_s++;
				msgPtr = (void *)t_s;
				counter += sizeof(short);
			}
			break;

			case rpcInt:
			{
				int *t_i = (int *)msgPtr;
				args[j] = (void *)t_i;
				t_i++;
				msgPtr = (void *) t_i;
				counter += sizeof(int);
			}
			break;

			case rpcLong:
			{
				long *t_l = (long *)msgPtr;
				args[j] = (void *)t_l;
				t_l++;
				msgPtr = (void *) t_l;
				counter += sizeof(long);
			}
			break;

			case rpcFloat:
			{
				float *t_f = (float *)msgPtr;
				args[j] = (void *)t_f;
				t_f++;
				msgPtr = (void *) t_f;
				counter += sizeof(float);
			}
			break;

			case rpcDouble:
			{
				double *t_d = (double *)msgPtr;
				args[j] = (void *)t_d;
				t_d++;
				msgPtr = (void *) t_d;
				counter += sizeof(double);
			}
			break;

			case rpcString:
			{
				char *tempString = (char *)msgPtr;	//get a pointer to te start
				int i = 0; //store length of string
				for(; *tempString != '\0'; tempString++, i++) {}	//scan through data until we hit the null character
				tempString  = (char *)malloc((i + 1) * sizeof(char));		//allocate proper amount of space
				char *temp_char = (char *)msgPtr;
				int k = 0;
				for(; k < i; k++) {
					tempString[k] = *temp_char;
					temp_char++;
					counter += sizeof(char);
				}	//copy the data
				tempString[k] = '\0';
				temp_char++;
				counter += sizeof(char);
				k++;
				//skip zero if name was padded for memory address alignment
				if (k % 4 != 0) { //equivalent to (k-1) % 4 == 0
					for(int z = 0; z < 4-(k % 4); z++) {
						temp_char++;
						counter += sizeof(char);
					}
				}
				msgPtr = (void *)temp_char;
				args[j] = (void *)tempString;	//assign to args pointer
			}
			break;
			default:
				cerr << "Unknown parameter type." << endl;
				return RESULT_FAILURE;
			break;
			} //end switch
		}
	}

	function *temp_func = (function *)msgPtr;
	unPackedData->f = *temp_func;

	unPackedData->argTypes = argTypes;	//assign pointers to destination struct
	unPackedData->args = args;

	return RESULT_SUCCESS;	//success!
}

// Marshalls the data used for communication to/from the binder.
// message is the block of data that is created from the marshall process
// bm is the data to be marshalled
// msgLength stores the calculated size of the marshalled data
// return indicates if the marshalling operation was successful or not
int binderPackData(void *message, binder_msg *bm, int *msgLength) {

	*msgLength = 0;

	//pointer to traverse through the block of data being created
	void *msgPtr = message;

	//marshall in request type information
	int *temp_req = (int *) msgPtr;
	*temp_req = (int) bm->requestType;
	temp_req++;
	msgPtr = (void *) temp_req;
	*msgLength += sizeof(int);

	//marshall in the function name in the message
	//remember that all binder messages must have a name
	//'\0' should be default case
	char *namePtr = bm->name;
	char *tempPtr = (char *)msgPtr;
	int nameLen = 0;
	for(; *namePtr != '\0'; namePtr++) {
		*tempPtr = *namePtr;
		tempPtr++;
		nameLen++;
		*msgLength += sizeof(char);
	}
	*tempPtr = '\0';
	tempPtr++;
	nameLen++;
	*msgLength += sizeof(char);

	//ensure memory address for next write is properly aligned
	//by forcing the next write to be on an even memory address
	if (nameLen % 4 != 0) {
		for(int i = 0; i < 4-(nameLen % 4); i++) {
			*tempPtr = 0;
			tempPtr++;
			*msgLength += sizeof(char);
		}
	}
	msgPtr = (void *)tempPtr;

	//marshall the argument type information
	//remember that all binder message structs must have argTypes array
	//argTypes[0] = 0 is default
	int numParams = 0;
	int *tempPtr1 = (int *)msgPtr;
	for(; bm->argTypes[numParams] != 0; numParams++) {
		/*cout << "ADDRESS OF TEMPTR: " << tempPtr1 << endl;
		cout << "TMPPTR POINTS TO: " << *tempPtr1 << endl;
		cout << "ARGYTPES POINTS TO: " << bm->argTypes[numParams] << endl;*/
		*tempPtr1 = bm->argTypes[numParams];
		tempPtr1++;
		*msgLength += sizeof(int);
	}
	//add the 0 at the end
	tempPtr1++;
	*msgLength += sizeof(int);
	msgPtr = (void *) tempPtr1;

	//marshall the function information
	//non-null function arrays must end with 0 as last element
	if(bm->functions != NULL) {
		//traverse through array of functions
		//and store the information
		function *tempPtr = (function *)msgPtr;
		function *funPtr = bm->functions;
		while(*funPtr != 0) {
			*tempPtr = *funPtr;
			funPtr++;
			tempPtr++;
			*msgLength += sizeof(function);
		}
		msgPtr = (void *) tempPtr;
	}
	//pad end of function array with one zero
	function *padPtr = (function *)msgPtr;
	*padPtr = 0;
	padPtr++;
	msgPtr = (void *) padPtr;
	*msgLength += sizeof(function);

	//marshall the server ip address information
	//non-null server ip address arrays must end with 0 as last element
	//size of servers array must match size of functions array by construction
	if(bm->servers != NULL) {
		unsigned long *tempPtr = (unsigned long *)msgPtr;

		//traverse through array of ip addresses
		//and store the information
		unsigned long *adPtr = (unsigned long *)bm->servers;
		while(*adPtr != 0) {
			*tempPtr = *adPtr;
			adPtr++;
			tempPtr++;
			*msgLength += sizeof(unsigned long);
		}
		msgPtr = (void *)tempPtr;
	}
	//pad end of server ip address array with zero
	unsigned long *pdPtr = (unsigned long *)msgPtr;
	*pdPtr = 0;
	pdPtr++;
	msgPtr = (void *)pdPtr;
	*msgLength += sizeof(unsigned long);

	return RESULT_SUCCESS;
}

// Demarshalls the data used for communication to/from the binder.
// message is the block of data that will be demarshalled
// bm is the version of the data that can be understood by the system
// return indicates if the demarshalling operation was successful or not
int binderUnpackData(void *message, binder_msg *dest_msg) {

	//pointer to traverse through the block of data being created
	void *msgPtr = message;

	//next block demarshalls the request type
	int *reqPtr = (int *)msgPtr;
	dest_msg->requestType = *reqPtr;
	reqPtr++;
	msgPtr = (void *)reqPtr;

	//next block demarshalls the function name
	char *tempString = (char *)msgPtr;
	//determine length of function name's string
	int i = 0;
	for(; *tempString != '\0'; tempString++, i++) {}
	//allocate memory for the demarshalled function name string
	tempString  = (char *)malloc(i*sizeof(char)+1);
	char *temp_char = (char *)msgPtr;
	int k;
	for (k = 0; k < i; k++) {
		tempString[k] = *temp_char;
		temp_char++;
	}
	tempString[k] = '\0';
	k++;
	temp_char++;
	//skip zero if name was padded for memory address alignment
	if (k % 4 != 0) { //equivalent to (k-1) % 4 == 0
		for(int i = 0; i < 4-(k % 4); i++) {
			temp_char++;
		}
	}
	msgPtr = (void *) temp_char;

	dest_msg->name = tempString;

	//next block demarshalls the argTypes
	int numParams = 0;
	//grab the number of parameters in argTypes, minus the ending 0
	int *temp_for_params = (int *)msgPtr;
	for(; *temp_for_params != 0; temp_for_params++) {
		numParams++;
	}
	//allocate memory for the argTypes
	int *argTypes = (int *)malloc((numParams + 1) * sizeof(int));
	for(int i = 0; i < numParams; i++) {
		int *temp2 = (int *)msgPtr;
		argTypes[i] = *temp2;
		temp2++;
		msgPtr = (void *)temp2;
	}
	//add and read in the last 0 into argTypes array
	int *t_int = (int *)msgPtr;
	argTypes[numParams] = 0;
	t_int++;
	msgPtr = (void *)t_int;
	dest_msg->argTypes = argTypes;

	//next block demarshalls the functions array
	function *temp_f = (function *)msgPtr;
	int numFuncs = 0;
	for(; *temp_f != 0; temp_f++){
		numFuncs++;
	}
	//allocate memory for the functions array
	function *functions = (function *)malloc((numFuncs + 1) * sizeof(function));
	for(int x = 0; x < numFuncs; x++) {
		function *tempF = (function *)msgPtr;
		functions[x] = *tempF;
		tempF++;
		msgPtr = (void *)tempF;
	}
	//add and read in the last 0 into functions array
	function *z = (function *)msgPtr;
	z++;
	msgPtr = (void *)z;
	functions[numFuncs] = 0;
	dest_msg->functions = functions;

	//next block demarshalls the server ip addresses array
	//length of servers array is size of functions array by construction
	unsigned long *lPtr = (unsigned long *)msgPtr;
	int numServs = numFuncs;
	//allocate memory for the servers array
	unsigned long *servers = (unsigned long *)malloc((numServs + 1) * sizeof(unsigned long));
	for(int y; y < numServs; y++) {
		unsigned long *tempS = (unsigned long *)msgPtr;
		servers[y] = *tempS;
		tempS++;
		msgPtr = (void *)tempS;
	}
	//add and read in the last 0 into servers array
	unsigned long *g = (unsigned long *)msgPtr;
	g++;
	msgPtr = (void *)g;
	servers[numServs] = 0;
	dest_msg->servers = servers;

	return RESULT_SUCCESS;

}

#endif
